package cn.iocoder.yudao.module.digital.service.cardkeyproduct;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.digital.dal.dataobject.cardkeyproduct.CardkeyProductJoinDO;
import cn.iocoder.yudao.module.digital.dal.redis.cardkeymanager.CardKeyManagerLockRedisDAO;
import cn.iocoder.yudao.module.digital.enums.ErrorCodeConstants;
import cn.iocoder.yudao.module.digital.enums.cardkeysecret.CardKeySourceEnum;
import cn.iocoder.yudao.module.digital.service.cardkeysecret.CardkeySecretService;
import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

import cn.iocoder.yudao.module.digital.controller.admin.cardkeyproduct.vo.*;
import cn.iocoder.yudao.module.digital.dal.dataobject.cardkeyproduct.CardkeyProductDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;

import cn.iocoder.yudao.module.digital.dal.mysql.cardkeyproduct.CardkeyProductMapper;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.digital.enums.ErrorCodeConstants.*;

/**
 * 卡密商品 Service 实现类
 *
 * @author 超管
 */
@Service
@Validated
@Slf4j
public class CardkeyProductServiceImpl implements CardkeyProductService {

    @Resource
    private CardkeyProductMapper cardkeyProductMapper;
    @Resource
    private CardkeySecretService cardkeySecretService;
    @Resource
    private ProductSkuApi productSkuApi;
    @Resource
    private CardKeyManagerLockRedisDAO lockRedisDAO;
    @Resource
    private TransactionTemplate transactionTemplate;

    @Override
    public Long createCardkeyProduct(CardkeyProductSaveReqVO createReqVO) {
        // 插入
        CardkeyProductDO cardkeyProduct = BeanUtils.toBean(createReqVO, CardkeyProductDO.class);
        cardkeyProductMapper.insert(cardkeyProduct);
        // 返回
        return cardkeyProduct.getId();
    }

    @Override
    public void updateCardkeyProduct(CardkeyProductSaveReqVO updateReqVO) {
        // 校验存在
        validateCardkeyProductExists(updateReqVO.getId());
        // 更新
        CardkeyProductDO updateObj = BeanUtils.toBean(updateReqVO, CardkeyProductDO.class);
        cardkeyProductMapper.updateById(updateObj);
    }

    @Override
    public void deleteCardkeyProduct(Long id) {
        // 校验存在
        validateCardkeyProductExists(id);
        // 删除
        cardkeyProductMapper.deleteById(id);
    }

    private void validateCardkeyProductExists(Long id) {
        if (cardkeyProductMapper.selectById(id) == null) {
            throw exception(CARDKEY_PRODUCT_NOT_EXISTS);
        }
    }

    @Override
    public CardkeyProductDO getCardkeyProduct(Long id) {
        return cardkeyProductMapper.selectById(id);
    }

    @Override
    public PageResult<CardkeyProductJoinDO> getCardkeyProductPage(CardkeyProductPageReqVO pageReqVO) {
        return cardkeyProductMapper.selectPageWithStock(pageReqVO);
    }

    /**
     * 导入卡密商品及密钥
     *
     * @param list
     */
    @Override
    public void importCardKeyProductAndSecret(List<CardKeyProductImportExcelVO> list) {
        // 查询已存在的product
//        final Set<String> productNoSet = list.stream().map(v -> v.getProductNo()).collect(Collectors.toSet());
//        final List<CardkeyProductDO> existedProductList = cardkeyProductMapper.getCardKeyProductByProductNo(productNoSet);
//        final Map<String, CardkeyProductDO> productNo2Product = CollectionUtils.convertMap(existedProductList, CardkeyProductDO::getProductNo);

        // 校验
        validateImportExcelVO(list);

        // 写入数据
        writeProductAndSecretData(list);
    }

    // 写入数据
    public void writeProductAndSecretData(List<CardKeyProductImportExcelVO> list) {
        // 写卡密密钥数据
        // list按照CardKeyProductImportExcelVO.productNo+denominationFixed进行分组
        final Map<String, List<CardKeyProductImportExcelVO>> productNo2SecretList = list.stream().collect(Collectors.groupingBy(v -> v.getProductNo() + v.getDenominationFixed().toPlainString()));
        for (List<CardKeyProductImportExcelVO> keyList : productNo2SecretList.values()) {
            if (CollUtil.isNotEmpty(keyList)) {
                final String productNo = keyList.get(0).getProductNo();
                final CardkeyProductDO product = cardkeyProductMapper.getCardKeyProductByProductNo(productNo);
                final CardKeySourceEnum source = CardKeySourceEnum.fromValue(product.getSource());

                final int denominationFixed = keyList.get(0).getDenominationFixed().multiply(new BigDecimal(100)).intValue();// 元转换为分
                lockRedisDAO.lockProduct(source, productNo, denominationFixed, () -> {
                    return transactionTemplate.execute(t -> {
                        log.info("写卡密密钥数据, source = {}, productNo = {}, denominationFixed = {}, keyListSize = {}",
                                source, productNo, denominationFixed, keyList.size());
                        cardkeySecretService.batchCreateCardKeySecret(source, keyList);
                        return null;
                    });
                });
            }
        }

//        // 更新库存
//        final Map<String, List<CardKeyProductImportExcelVO>> productNo2SecretList = CollectionUtils.convertMultiMap(list, CardKeyProductImportExcelVO::getProductNo);
//        for (Map.Entry<String, List<CardKeyProductImportExcelVO>> entry : productNo2SecretList.entrySet()) {
//            final String productNo = entry.getKey();
//            final List<CardKeyProductImportExcelVO> secretList = entry.getValue();
//            final Integer incrCount = secretList.size();
//            productSkuApi.updateSkuStockByCardKeyProductNo(productNo, incrCount);
//        }
    }

    // 写卡密产品数据
    private void writeProductData(CardKeyProductImportExcelVO vo) {
//        final Map<String, CardKeyProductImportExcelVO> map = CollectionUtils.convertMap(list, CardKeyProductImportExcelVO::getProductNo);
//        for (CardKeyProductImportExcelVO vo : map.values()) {
//            CardkeyProductDO existedProduct = productNo2Product.get(vo.getProductNo());
//            if (existedProduct != null) {
//                if (StrUtil.isNotEmpty(vo.getProductName())) {
//                    existedProduct.setProductName(vo.getProductName());
//                    cardkeyProductMapper.updateById(existedProduct);
//                }
//            } else {
//                existedProduct = new CardkeyProductDO();
//                existedProduct.setSource(CardKeySourceEnum.MANUAL.getValue());
//                existedProduct.setProductNo(vo.getProductNo());
//                existedProduct.setProductName(vo.getProductName());
//                existedProduct.setCurrencyCode(vo.getCurrencyCode());
//                final int denominationFixed = vo.getDenominationFixed().multiply(new BigDecimal(100)).intValue();// 元转换为分
//                existedProduct.setDenominationFixed(denominationFixed);
//                existedProduct.setCustomDenomination(false);
//                cardkeyProductMapper.insert(existedProduct);
//            }
//        }

        final CardkeyProductDO existedProduct = new CardkeyProductDO();
        existedProduct.setSource(CardKeySourceEnum.MANUAL.getValue());
        existedProduct.setProductNo(vo.getProductNo());
        existedProduct.setProductName(vo.getProductName());
        existedProduct.setCurrencyCode(vo.getCurrencyCode());

        if (vo.getDenominationMax() != null && vo.getDenominationMin() != null) {
            // 自定义面值
            existedProduct.setCustomDenomination(true);

            final int denominationMax = vo.getDenominationMax().multiply(new BigDecimal(100)).intValue();// 元转换为分
            existedProduct.setDenominationMax(denominationMax);

            final int denominationMin = vo.getDenominationMin().multiply(new BigDecimal(100)).intValue();// 元转换为分
            existedProduct.setDenominationMin(denominationMin);
        } else {
            // 固定面值
            existedProduct.setCustomDenomination(false);

            final int denominationFixed = vo.getDenominationFixed().multiply(new BigDecimal(100)).intValue();// 元转换为分
            existedProduct.setDenominationFixed(denominationFixed);
        }

        cardkeyProductMapper.insert(existedProduct);
    }

    private void validateImportExcelVO(List<CardKeyProductImportExcelVO> list) {
        int row = 0;
        for (CardKeyProductImportExcelVO vo : list) {
            row++;
            final CardkeyProductDO existedProduct = cardkeyProductMapper.getCardKeyProductByProductNo(vo.getProductNo());
            if (existedProduct != null) {
                if (!vo.getCurrencyCode().equals(existedProduct.getCurrencyCode())) {
                    log.warn("导入卡密商品及密钥-货币跟当前数据库中的不一致, row = {}, productNo = {}, existedCurrencyCode = {}, currencyCode = {}, vo = {}",
                            row, vo.getProductNo(), existedProduct.getCurrencyCode(), vo.getCurrencyCode(), vo);
                    throw ServiceExceptionUtil.exception(ErrorCodeConstants.CARDKEY_DEFAULT_ERROR, String.format("第[%s]行CDK编号为[%s]的[货币]跟当前数据库中的不一致", row, vo.getProductNo()));
                }

                final int denominationFixed = vo.getDenominationFixed().multiply(new BigDecimal(100)).intValue();// 元转换为分
                if (existedProduct.getCustomDenomination()) {
                    // 自定义面值
                    if (denominationFixed < existedProduct.getDenominationMin() || denominationFixed > existedProduct.getDenominationMax()) {
                        log.warn("导入卡密商品及密钥-商品面值不在自定义面值的区间内, row = {}, productNo = {}, denominationMin = {}, denominationMax = {}, denominationFixed = {}, vo = {}",
                                row, vo.getProductNo(), existedProduct.getDenominationMin(), existedProduct.getDenominationMax(), denominationFixed, vo);
                        throw ServiceExceptionUtil.exception(ErrorCodeConstants.CARDKEY_DEFAULT_ERROR, String.format("第[%s]行CDK编号为[%s]的[商品面值]不在自定义面值的区间内", row, vo.getProductNo()));
                    }
                } else {
                    // 固定面值
                    if (denominationFixed != existedProduct.getDenominationFixed()) {
                        log.warn("导入卡密商品及密钥-商品面值跟当前数据库中的不一致, row = {}, productNo = {}, existedDenominationFixed = {}, denominationFixed = {}, vo = {}",
                                row, vo.getProductNo(), existedProduct.getDenominationFixed(), denominationFixed, vo);
                        throw ServiceExceptionUtil.exception(ErrorCodeConstants.CARDKEY_DEFAULT_ERROR, String.format("第[%s]行CDK编号为[%s]的[商品面值]跟当前数据库中的不一致", row, vo.getProductNo()));
                    }
                }
            } else {
                if (vo.getDenominationMin() != null && vo.getDenominationMax() != null) {
                    // 自定义面值
                    final int denominationFixed = vo.getDenominationFixed().multiply(new BigDecimal(100)).intValue();// 元转换为分
                    final int denominationMin = vo.getDenominationMin().multiply(new BigDecimal(100)).intValue();// 元转换为分
                    final int denominationMax = vo.getDenominationMax().multiply(new BigDecimal(100)).intValue();// 元转换为分
                    if (denominationFixed < denominationMin || denominationFixed > denominationMax) {
                        log.warn("导入卡密商品及密钥-商品面值不在自定义面值的区间内, row = {}, productNo = {}, denominationMin = {}, denominationMax = {}, denominationFixed = {}, vo = {}",
                                row, vo.getProductNo(), denominationMin, denominationMax, denominationFixed, vo);
                        throw ServiceExceptionUtil.exception(ErrorCodeConstants.CARDKEY_DEFAULT_ERROR, String.format("第[%s]行CDK编号为[%s]的[商品面值]不在自定义面值的区间内", row, vo.getProductNo()));
                    }
                }

                writeProductData(vo);
            }
        }
    }

    @Override
    public CardkeyProductDO getCardKeyProductByNo(String cardKeyProductNo) {
        final LambdaQueryWrapper<CardkeyProductDO> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(CardkeyProductDO::getProductNo, cardKeyProductNo);
        final CardkeyProductDO cardkeyProductDO = cardkeyProductMapper.selectOne(wrapper);
        return cardkeyProductDO;
    }

    @Override
    public Long createCardkeyProduct(CardkeyProductDO productDO) {
        cardkeyProductMapper.insert(productDO);
        return productDO.getId();
    }

    @Override
    public int updateCardkeyProduct(CardkeyProductDO productDO) {
        return cardkeyProductMapper.updateById(productDO);
    }

    @Override
    public List<CardkeyProductDO> selectBySource(CardKeySourceEnum sourceEnum) {
        return cardkeyProductMapper.selectBySource(sourceEnum);
    }
}